var db = require("./libs/db"); 
var mqtt = require('mqtt');
const kurento = require("kurento-client"); 

class TKmsSvc{
    constructor(){
        this.config={
            appId:"vSport",
            clientId:"",
            kms:{
                kmsUrl:"wss://wss.hhdata.cn:8433/kurento" ,
                tagKey:"kmsManager"
            },
            db:{
                dbKey:'vSport',
                dbInfo:{
                    host:"tjiot.hhdata.cn" ,
                    port:53306,
                    uid:"root",
                    pwd:"hhuc1115",
                    db:"vSport" , 
                    sqlPath:"D:/gitee/hhudev/web/apps/tm/sqls"
                }
            },
            mq:{
                url:"tcp://gmggf8g.mqtt.iot.bj.baidubce.com:1883",
                uid:"gmggf8g/peer",
                pwd:"a52bwKg22dCAuQzB" 
            }
        };
        this.db = new db.TDBMySql();
        this.kmsClient = null;
        this.mqClient =null;
        this.kmsObjIdDict={};
        this.kmsObjCodeDict={};
        this.sessions = {};
        this.candilateBufs = {};
    }
    init(){
        var me = this;
        if( this.config.clientId ==""){
            this.config.clientId = ['kms',(new Date()).getTime(), parseInt(1000*Math.random())].join("");
        }
        me.db.apps[me.config.db.dbKey] = me.config.db.dbInfo;    
    }
    openSvc(){
        var me = this;
        return new Promise((success , faild)=>{
            try{    
                me.openMq().then(()=>{
                    return me.getClient();
                }).then(client=>{
                    console.log("start service . ");
                    console.log("appId:", me.config.appId );
                    console.log("clientId:", me.config.clientId );
                    console.log("db:", me.config.db.dbKey );
                    console.log("mq:", me.config.mq.url );
                    console.log("kms:", client );
                })
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    openMq(){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                var options={
                    username: me.config.mq.uid ,
                    password: me.config.mq.pwd ,
                    clientId: me.config.clientId
                };
                var client=mqtt.connect( me.config.mq.url , options );
                me.mqClient = client;
                client.on('message', function (topic, message) {
                    var msg=JSON.parse(message.toString());   
                    console.log(msg);
                    try{
                        if( msg.msgId=="offline"){
                            ;
                        }
                        else if( msg.msgId=="reqSession"){
                            var session ={
                                sessionId:["session" , ( new Date()).getTime() , parseInt(1000*Math.random())].join(''),
                                clientId: msg.msgBody.clientId,
                                reqId: msg.reqId ,
                                end: null
                            }
                            me.candilateBufs[session.sessionId] = [];
                            me.sessions[session.sessionId] = session;                                        
                            var topic = 'hh/'+ me.config.appId+"/"+session.clientId;
                            var respMsg ={
                                msgId:'respSession' ,
                                reqId: msg.reqId ,
                                msgBody:{
                                    clientId: session.clientId ,
                                    sessionId: session.sessionId
                                }
                            }
                            client.publish(topic , JSON.stringify(respMsg));
                        }
                        else if( msg.msgId=="sdpOffer"){                            
                            var session = me.sessions[msg.msgBody.sessionId];
                            var offer = msg.msgBody.sdpOffer; 
                            var code = msg.msgBody.code;
                            me.kmsClient.appPipe.create("WebRtcEndpoint",function(erEnd , end){
                                me.registKmsObj( end , code , session.clientId ).then(obj=>{
                                    session.end = end ;
                                    var topic = 'hh/'+ me.config.appId+"/"+session.clientId ;
                                    while( me.candilateBufs[session.sessionId] && me.candilateBufs[session.sessionId].length>0){
                                        var candidate = me.candilateBufs[session.sessionId].shift();
                                        end.addIceCandidate(candidate);     
                                        console.log('load candidate');
                                    }
                
                                    end.on('OnIceCandidate', function(event) {
                                        var candidate = kurento.getComplexType('IceCandidate')(event.candidate);
                                        var msgCand ={
                                            msgId:"candidate", 
                                            msgBody:{
                                                sessionId: session.sessionId ,
                                                candidate: candidate,
                                                endId: end.id
                                            }
                                        }
                                        me.mqClient.publish(topic , JSON.stringify(msgCand));
                                    });
                                    end.processOffer( offer, function(erAnswer , sdpAnswer){ 

                                        var msgAnswer ={
                                            msgId:"respOffer", 
                                            reqId: msg.reqId ,
                                            msgBody:{
                                                sessionId: session.sessionId ,
                                                sdpAnswer: sdpAnswer,
                                                endId: end.id
                                            }
                                        }
                                        end.gatherCandidates(function(ere){
                                            me.mqClient.publish(topic , JSON.stringify(msgAnswer)); 
                                        })
                                    })
                                })
                            })
                        }
                        else if( msg.msgId=="peCandidate"){                            
                            var session = me.sessions[msg.msgBody.sessionId];
                            var candidate = msg.msgBody.cnadadite; 
                            if( session && session.end){
                                session.end.addIceCandidate(candidate);
                                console.log('rec pe candidate. add');
                            }
                            else{
                                me.candilateBufs[session.sessionId].push(candidate);
                                console.log('rec pe candidate. push');
                            }
                            
                        }
                        else if( msg.msgId=="connectMedia"){      
                            var src = me.getKmsObjById( msg.msgBody.srcId );
                            var target = me.getKmsObjById( msg.msgBody.targetId );
                            var mediaType = me.getKmsObjById( msg.msgBody.mediaType );
                            if( src && src!=null && target && target!=null){
                                if ( mediaType=="AUDIO" || mediaType=="VIDEO"){
                                    src.connect(target , mediaType , function(erConn){
                                        if( erConn && erConn!=null){
                                            console.log(erConn);
                                        }
                                    })
                                }
                                else{                                    
                                    src.connect(target , function(erConn){
                                        if( erConn && erConn!=null){
                                            console.log(erConn);
                                        }
                                    })
                                }
                            }
                        }
                        else if( msg.msgId=="loadPlayer"){      
                            var code = me.getKmsObjById( msg.msgBody.code );
                            var srcUrl = me.getKmsObjById( msg.msgBody.url );
                            var reqId = msg.reqId;
                            var topic = 'hh/'+ me.config.appId+"/"+session.clientId ;
                            var respMsgBody={
                                msgId:"respLoadPlayer",
                                reqId: reqId ,
                                msgBody:{
                                    playerId:""
                                }
                            };
                            var player = me.getKmsObjByCode(code);
                            var createPlayer = function(){
                                me.kmsClient.appPipe.create("PlayerEndpoint",{uri: srcUrl},function(erEnd , playerEnd){
                                    me.registKmsObj( playerEnd , code , "svr" ).then(obj=>{
                                        player = obj;
                                        player.on("EndOfStream" , function(err){
                                            player.play();
                                        })
                                        player.play();
                                        respMsgBody.msgBody.playerId = player.id;
                                        me.mqClient.publish(topic , JSON.stringify(respMsgBody));
                                    });
                                });
                            }
                            if( player && player!=null){
                                respMsgBody.msgBody.playerId = player.id;
                                player.getState( function(erSate , state){
                                    if( state=="STOP"){
                                        player.play();
                                    }
                                })
                                me.mqClient.publish(topic , JSON.stringify(respMsgBody));                                
                            }
                            else{
                                createPlayer();
                            }
                        }
                        else {
                            console.log(msg)
                        }
                    }
                    catch(exr){
                        console.log(exr)
                    }
                }); 
                var topic = 'hh/'+me.config.appId+"/svr/#";
                client.subscribe([topic]); 
                console.log('mq topic :' , topic);
                success();
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    getClient(){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                var hasCreated = me.kmsClient && me.kmsClient!=null ;
                var createClient = function(){
                    me.kmsClient = null;
                    kurento( me.config.kms.kmsUrl, function(erClient , client){
                        me.kmsClient = client;
                        if( client && client!=null){
                            client.create("MediaPipeline").then(pipe=>{
                                client.appPipe =pipe;
                                return me.registKmsObj(pipe , me.config.appId , me.config.clientId);
                            }).then(obj=>{
                                return me.loadKmsObjs(client)
                            }).then(()=>{
                                success(client);
                            })
                        }
                        else{
                            console.log('-------------------------------------------------------------');
                            console.log(erClient);
                            console.log('create kms client faild. kmsUrl:' , me.config.kms.kmsUrl);
                            success(null);
                        }
                    })
                }
                if( hasCreated){
                    me.kmsClient.getServerManager( function(erSvr , svr){
                        if( svr && svr!=null){
                            success(me.kmsClient);
                        }
                        else{
                            createClient();
                        }
                    })
                }
                else{
                    createClient();
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    loadKmsObjs(client){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                var freeIds = [];
                var sql ="SELECT * FROM v_currentKmsObj";
                me.db.query( me.config.db.dbKey , sql , {} , function(res){
                    var items = res.result;
                    var loadItem = function(){
                        if( items.length>0){
                            var item = items.shift();
                            var kmsId = item.kmsId;
                            client.getMediaobjectById(kmsId, function(erObj , obj){
                                if( obj && obj!=null ){
                                    obj.info = item;
                                    me.kmsObjCodeDict[item.code] = obj;
                                    me.kmsObjIdDict[item.kmsId] = obj;
                                    console.log(' load kms object.' , item);
                                }
                                else{
                                    console.log(' kms object is destroy.' , item);
                                    freeIds.push(item.objId);
                                }
                                loadItem();
                            })
                        }
                        else{
                            if( freeIds.length>0){
                                sql = 'delete from T_KmsObj where objId in ('+freeIds.join(',')+')';
                                me.db.query( me.config.db.dbKey , sql , {} , function(resFree){
                                    success();
                                });
                            }
                            else{
                                success();
                            }
                        }
                    }
                    loadItem();
                })
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    registKmsObj(obj , code , clientId){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                if( obj && obj!=null && obj.id){
                    var sql = 'insert into T_KmsObj(code,kmsId,clientId,createTm) values (:code,:kmsId,:clientId,unix_timestamp(now()))';
                    var ps ={
                        code: code ,
                        kmsId: obj.id ,
                        clientId: clientId
                    }
                    me.db.query( me.config.db.dbKey , sql , ps , function(resFree){
                        if( resFree && resFree.result && resFree.result.insertId){
                            ps.objId = resFree.insertId;
                            obj.info = ps;
                            me.kmsObjCodeDict[ps.code] = obj;
                            me.kmsObjIdDict[ps.kmsId] = obj;
                            success(obj);
                        }
                        else{
                            success(null);
                        }
                    });
                }
                else{
                    success(obj);
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    freeKmsObj( kmsId){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                if(me.kmsObjIdDict[kmsId]){
                    var obj = me.kmsObjIdDict[kmsId];
                    delete me.kmsObjIdDict[kmsId];
                    if( me.kmsObjCodeDict[obj.code]){
                        delete me.kmsObjCodeDict[obj.code];
                    }
                    var sql = "delete from T_KmsObj where objId='"+kmsId+"'";
                    me.db.query(me.config.db.dbKey , sql , {} , function(res){
                        obj.release(function(){
                            success();
                        })
                    })
                }
                else{
                    success();
                }
            }
            catch(er){
                console.log(er);
                success();
            }
        })
    }
    getKmsObjByCode(code){
        var me = this;
        return me.kmsObjCodeDict[code]?me.kmsObjCodeDict[code]: null;
    }
    getKmsObjById(kmsId){
        var me = this;
        return me.kmsObjIdDict[kmsId]?me.kmsObjIdDict[kmsId]: null;
    } 
    onRequestCreatePlayer(msgBody){
        var me = this;
        return new Promise((success , faild)=>{
            try{
                var code = msgBody.code ;
                var clientId = msgBody.clientId ;
                var url = msgBody.url;
                var obj = me.getKmsObjByCode(code);
                var respObj = function(){
                    if( obj && obj!=null){
                        var topic = "/"+clientId;
                        var msg ={
                            msgId:"respCreatePlayer",
                            msgDir:"sp",
                            reqId: msgBody.reqId,
                            msgBody:obj.info
                        };
                        me.mqClient.publish(topic , JSON.stringify(msg));
                        success("request create player." , obj.info);
                    }
                    else{
                        success("request create player.   faild"  );
                    }
                }
                if( obj==null){
                    me.kmsClient.appPipe.create("PlayerEndpoint" , { uri: url} , function(erPlayer , playerEnd){
                        me.registKmsObj(playerEnd , code , clientId).then(pEnd=>{
                            obj = pEnd;
                            obj.on("EndOfStream", function(){
                                obj.play();
                            })
                            respObj();
                        })
                    })
                }
                else{
                    obj.getState(function(erState , state){
                        if( state=="STOP"){
                            obj.play(function(){
                                respObj();
                            })
                        }
                        else{
                            respObj();
                        }
                    })
                    respObj();
                }
            }
            catch(er){
                console.log(er);
                success(null);
            }
        });
    }  
}


var kmsSvc = new TKmsSvc();
kmsSvc.init();
kmsSvc.getClient().then(client=>{
    return kmsSvc.openSvc()
}).then(()=>{
    console.log('open svc.')
});